﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Data;
/*
	Higher level class to wrap a selection list where
	the data is separate from the presentation
	this class is responsible for populating the options as well
	Construct with a DataTable of one or more columns.
	Configure a display column and a data column. They may be the same
*/
namespace SimpleEntry
{
	public class CodeListControl : IEditControl
	{
		// Construct with a ComboBox or ListBox control
		// a DataTable containing the selection list and indexes to the data column and display column (may be the same)

		/// <summary>
		/// Class to provide an IControl interface to a selection control for the standard entry system.
		/// It currently expects either a ListBox or a ComboBox winforms control and will throw an exception 
		/// if any other control type is sent in. Additional parameters configure the code list lookup
		/// </summary>
		/// <param name="control">winforms list-based control (ComboBox or ListBox)</param>
		/// <param name="CodeListTable">DataTable with rows containing the selections</param>
		/// <param name="codeIndex">column index in the code table to use for values to set in the data element</param>
		/// <param name="displayIndex">column index in the code table for values to display in the control. The
		/// display index may be the same as the codeIndex</param>
		public CodeListControl(Control control, DataTable CodeListTable, int codeIndex, int displayIndex)
		{
			// controls supported
			// remove this if allowing override of class for other list-type controls (DataGridView/ListControl)
			if (control.GetType() != typeof(System.Windows.Forms.ListBox) &&
				control.GetType() != typeof(System.Windows.Forms.ComboBox))
				throw new Exception(String.Format("{0} is not a valid control to use to initialise a CodeListControl", control.GetType()));
			this.m_Control = control;
			this.m_CodeList = CodeListTable;
			this.m_CodeCol = codeIndex;
			this.m_DisplayCol = displayIndex;
			PopulateControl();
		}

		// IEditControl Interface 
		// Note this property deals solely with the code value not the display string
		public String Value
		{
			get { return this.Selected(); }
			set { SetSelection(value); }
		}

		public Control FormControl
		{
			get { return m_Control; }
			set { m_Control = value; }
		}

		// Populate the control items one per row using the display column 
		// needs extending if filtering is implemented
		private void PopulateControl()
		{
			foreach (DataRow dr in m_CodeList.Rows)
			{
				String s = dr[this.m_DisplayCol].ToString();
				AddItem(s); // overridable method in theory
			}
		}

		// Interface implementation of propert Value set
		private void SetSelection(string value)
		{
			// Items to iterate is abstracted in case filtering is implemented
			for (int idx = 0; idx < ItemCount(); ++idx)
			{
				// Work with data in the DataTable not the control
				String sel = ItemAt(idx);  // abstracted in case filtering is implemented
				if (sel == value)
				{
					Select(idx);  // overridable method in theory
					return;
				}
			}
		}

		// Interface implementation of propert Value get
		private string Selected()
		{
			int selectedIndex = SelectedIndex(); // overridable method in theory
			if (selectedIndex == -1)
				return "";
			String selected = ItemAt(selectedIndex);  // Work with data in the DataTable not the control
			return selected;
		}

		//////////////////////////////////////////////////
		// override if you want to filter the control items
		//
		protected virtual int ItemCount()
		{
			return m_CodeList.Rows.Count;
		}

		protected virtual String ItemAt(int idx)
		{
			DataRow dr = m_CodeList.Rows[idx];
			return dr[this.m_CodeCol].ToString();
		}
		//
		////////////////////////////////////////////////////
		
		///////////////////////////////////////
		// hacky stuff. Override if not using a List or a Combo.
		protected virtual int SelectedIndex()
		{
			ListBox lb = m_Control as ListBox;
			if (lb != null)	
				return lb.SelectedIndex;
			ComboBox cb = m_Control as ComboBox;
			if (cb != null)
				return cb.SelectedIndex;
			// ought to throw
			throw new InvalidCastException(String.Format("{0} is not a valid control to use with a CodeListControl", m_Control.GetType()));
		}

		protected virtual void Select(int idx)
		{
			ListBox lb = m_Control as ListBox;
			if (lb != null)
			{
				lb.SelectedIndex = idx;
				return;
			}
			ComboBox cb = m_Control as ComboBox;
			if (cb != null)
			{
				cb.SelectedIndex = idx;
				return;
			}
			// ought to throw
			throw new InvalidCastException(String.Format("{0} is not a valid control to use with a CodeListControl", m_Control.GetType()));
		}

		protected virtual void AddItem(string s)
		{
			ListBox lb = m_Control as ListBox;
			if (lb != null)
			{
				lb.Items.Add(s);
				return;
			}
			ComboBox cb = m_Control as ComboBox;
			if (cb != null)
			{
				cb.Items.Add(s);
				return;
			}
			// ought to throw
			throw new InvalidCastException(String.Format("{0} is not a valid control to use with a CodeListControl", m_Control.GetType()));
		}
		//
		///////////////////////////////////////

		Control m_Control;
		DataTable m_CodeList;
		int m_CodeCol;
		int m_DisplayCol;
	}


}
